package com.platform.zuul.filter;

import com.apache.passport.common.PassportHelper;
import com.apache.passport.common.XmlWhiteUtils;
import com.apache.tools.StrUtil;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.log4j.Logger;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URL;
import java.util.Map;

/**
 * description: 限流过滤器
 *
 * @author dyh 创建时间：2018年03月19日
 */
@Component
public class RateLimitZuulFilter extends ReqPermissionFilter {
    Logger log = Logger.getLogger(getClass());
    //    private final RateLimiter rateLimiter = RateLimiter.create(1000.0);// 每秒不超过1000个任务被提交

    private Map<String, RateLimiter> map = Maps.newConcurrentMap();

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        // 这边的order一定要大于org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter的order
        // 也就是要大于5
        // 否则，RequestContext.getCurrentContext()里拿不到serviceId等数据。
        return Ordered.LOWEST_PRECEDENCE;
    }

    @Override
    public boolean shouldFilter() {
        // 这里可以考虑弄个限流开启的开关，开启限流返回true，关闭限流返回false
        return true;
    }

    @Override
    public Object run() {
        try {
            RequestContext currentContext = RequestContext.getCurrentContext();
            HttpServletResponse response = currentContext.getResponse();
            HttpServletRequest request = currentContext.getRequest();
            log.debug("sessionId="+request.getSession().getId());
            String uri = request.getRequestURI();//获取uri信息
            String suffix = PassportHelper.getInstance().parseUrlSuffix(uri);//获取后缀名
            if (StrUtil.isNotNull(suffix)) {//如果存在后缀为图片,css等格式,直接跳过,不拦截
                suffix = suffix.toLowerCase();//后缀名小写
                if (XmlWhiteUtils.SUFFIX.contains(suffix)) {
                    return null;
                }
            }
            // StackTraceElement stack[] = Thread.currentThread().getStackTrace();
            String key = String.valueOf(RequestContext.getCurrentContext().get("serviceId"));
            if (StringUtils.isEmpty(key) || "null".equalsIgnoreCase(key)) {
                URL routeHost = RequestContext.getCurrentContext().getRouteHost();
                if (routeHost != null) {
                    key = routeHost.toString();
                }
            }
            if (!map.containsKey(key)) {
                map.put(key, RateLimiter.create(200.0));//每秒不超过200个任务被提交
            }
            RateLimiter rateLimiter = map.get(key);

            if (!rateLimiter.tryAcquire()) {//使用非阻塞的形式达到降级运行的目的
                HttpStatus httpStatus = HttpStatus.TOO_MANY_REQUESTS;
                response.setContentType(MediaType.TEXT_PLAIN_VALUE);
                response.setStatus(httpStatus.value());
                response.getWriter().append(httpStatus.getReasonPhrase());
                currentContext.setSendZuulResponse(false);
                throw new ZuulException(httpStatus.getReasonPhrase(), httpStatus.value(),
                        httpStatus.getReasonPhrase());
            }
            if(key.toLowerCase().indexOf("sso-server")!=-1){
                String tokenId = PassportHelper.getInstance().getCurrCookie(request);
                if(StrUtil.isNotNull(tokenId)){
                    String value = PassportHelper.getInstance().getCurrCookie(request, "_uc.sso");
                    currentContext.addZuulRequestHeader("zuulucsso", value);
                    currentContext.addZuulRequestHeader("zuultokenid", tokenId);
                }
            }else {
                String goUrl = this.runPermission(key);
                if (StrUtil.isNotNull(goUrl)) {
                    response.sendRedirect(goUrl);
                }
            }
        } catch (Exception e) {
            ReflectionUtils.rethrowRuntimeException(e);
        }
        return null;
    }
}
